package cn.monkey.family.rbac.dsl.http.jakarta;

import cn.monkey.family.rbac.dsl.http.HttpRequestPredicate;
import cn.monkey.family.rbac.dsl.http.HttpRequestPredicateDefinition;
import com.google.common.base.Strings;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;

import java.util.Map;

public class DefaultHttpServletRequestPredicate implements JakartaHttpServletRequestPredicate {

    private final HttpRequestPredicateDefinition httpRequestPredicateDefinition;

    private final AntPathMatcher antPathMatcher;

    public DefaultHttpServletRequestPredicate(HttpRequestPredicateDefinition httpRequestPredicateDefinition,
                                              AntPathMatcher antPathMatcher) {
        this.httpRequestPredicateDefinition = httpRequestPredicateDefinition;
        this.antPathMatcher = antPathMatcher;
    }

    @Override
    public int match(HttpServletRequest httpServletRequest) {
        int test = this.testPath(httpServletRequest);
        if ((test & HttpRequestPredicate.PredicateResult.PATH_MATCH) == 0) {
            return 0;
        }
        test = test | this.testMethod(httpServletRequest);
        if ((test & PredicateResult.METHOD_MATCH) == 0) {
            return test;
        }

        test = test | this.testHeaders(httpServletRequest);
        if ((test & PredicateResult.HEADER_MATCH) == 0) {
            return test;
        }
        return test | this.testParams(httpServletRequest);
    }

    private int testParams(HttpServletRequest httpServletRequest) {
        Map<String, String> params = this.httpRequestPredicateDefinition.getParams();
        if (CollectionUtils.isEmpty(params)) {
            return PredicateResult.PARAM_MATCH;
        }
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String param = httpServletRequest.getParameter(entry.getKey());
            if (Strings.isNullOrEmpty(param)) {
                return 0;
            }
            if (!param.equals(entry.getValue())) {
                return 0;
            }
        }
        return PredicateResult.PARAM_MATCH;
    }

    private int testHeaders(HttpServletRequest httpServletRequest) {
        Map<String, String> headers = this.httpRequestPredicateDefinition.getHeaders();
        if (CollectionUtils.isEmpty(headers)) {
            return PredicateResult.HEADER_MATCH;
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            String header = httpServletRequest.getHeader(entry.getKey());
            if (Strings.isNullOrEmpty(header)) {
                return 0;
            }
            if (!header.equals(entry.getValue())) {
                return 0;
            }
        }
        return PredicateResult.HEADER_MATCH;
    }

    private int testMethod(HttpServletRequest httpServletRequest) {
        String method = this.httpRequestPredicateDefinition.getMethod();
        if (Strings.isNullOrEmpty(method)) {
            return PredicateResult.METHOD_MATCH;
        }
        return method.equals(httpServletRequest.getMethod()) ? PredicateResult.METHOD_MATCH : 0;
    }

    private int testPath(HttpServletRequest httpServletRequest) {
        String path = this.httpRequestPredicateDefinition.getPath();
        if (Strings.isNullOrEmpty(path)) {
            return PredicateResult.PATH_MATCH;
        }
        String servletPath = httpServletRequest.getServletPath();
        if (path.contains("/**")) {
            return this.antPathMatcher.match(path, servletPath) ? PredicateResult.PATH_MATCH : 0;
        }
        return path.equals(servletPath) ? PredicateResult.PATH_MATCH : 0;
    }
}
